#include "precompiled.hpp"

#include "native.hpp"
#include "exec_context.hpp"

///////////////////////////////////////////////////////////////////////////////////////
////// Class for native rules
///////////////////////////////////////////////////////////////////////////////////////
class native_rule : public jam_rule
{
	native_rule_entry::rule_func rule_;
public:
	native_rule(const native_rule_entry &ent, jam_context *context, jam_module *module) :
	  jam_rule(context,module,ent.rule_name_), rule_(ent.rule_)
	{
		assert(ent.param_names_.size()==ent.param_types_.size());
		for(size_t f=0,fend=ent.param_names_.size();f!=fend;++f)
		{
			jam_rule::param_type tp=ent.param_types_[f];
			assert(tp!=jam_rule::none);
			if (tp==jam_rule::sublist)
				add_optional_param(ent.param_names_[f]);
			else
				add_param(tp,ent.param_names_[f]);
		}
	}
private:
	virtual void do_invoke(jam_frame *frame,jam_list *res)
	{
		rule_(frame,res);
	}
};

///////////////////////////////////////////////////////////////////////////////////////
////// Native rule registrator
///////////////////////////////////////////////////////////////////////////////////////
native_rule_entry::native_rule_entry(const jam_string &module, const jam_string &rule_name, 
	rule_func rule) : module_(module), rule_name_(rule_name), rule_(rule)
{	
}

native_rule_entry::native_rule_entry(const jam_string &module, const jam_string &rule_name
	,rule_func rule
	,jam_rule::param_type tp1,const jam_string &nm1
	) : module_(module), rule_name_(rule_name), rule_(rule)
{
	param_types_.push_back(tp1); param_names_.push_back(nm1);
}

native_rule_entry::native_rule_entry(const jam_string &module, const jam_string &rule_name
	,rule_func rule
	,jam_rule::param_type tp1,const jam_string &nm1
	,jam_rule::param_type tp2,const jam_string &nm2
	) : module_(module), rule_name_(rule_name), rule_(rule)
{
	param_types_.push_back(tp1); param_names_.push_back(nm1);
	param_types_.push_back(tp2); param_names_.push_back(nm2);
}

native_rule_entry::native_rule_entry(const jam_string &module, const jam_string &rule_name
	,rule_func rule
	,jam_rule::param_type tp1,const jam_string &nm1
	,jam_rule::param_type tp2,const jam_string &nm2
	,jam_rule::param_type tp3,const jam_string &nm3
	) : module_(module), rule_name_(rule_name), rule_(rule)
{
	param_types_.push_back(tp1); param_names_.push_back(nm1);
	param_types_.push_back(tp2); param_names_.push_back(nm2);
	param_types_.push_back(tp3); param_names_.push_back(nm3);
}

native_rule_entry::native_rule_entry(const jam_string &module, const jam_string &rule_name
	,rule_func rule
	,jam_rule::param_type tp1,const jam_string &nm1
	,jam_rule::param_type tp2,const jam_string &nm2
	,jam_rule::param_type tp3,const jam_string &nm3
	,jam_rule::param_type tp4,const jam_string &nm4
	) : module_(module), rule_name_(rule_name), rule_(rule)
{
	param_types_.push_back(tp1); param_names_.push_back(nm1);
	param_types_.push_back(tp2); param_names_.push_back(nm2);
	param_types_.push_back(tp3); param_names_.push_back(nm3);
	param_types_.push_back(tp4); param_names_.push_back(nm4);
}

native_rule_entry::native_rule_entry(const jam_string &module, const jam_string &rule_name
	,rule_func rule
	,jam_rule::param_type tp1,const jam_string &nm1
	,jam_rule::param_type tp2,const jam_string &nm2
	,jam_rule::param_type tp3,const jam_string &nm3
	,jam_rule::param_type tp4,const jam_string &nm4
	,jam_rule::param_type tp5,const jam_string &nm5
	) : module_(module), rule_name_(rule_name), rule_(rule)
{
	param_types_.push_back(tp1); param_names_.push_back(nm1);
	param_types_.push_back(tp2); param_names_.push_back(nm2);
	param_types_.push_back(tp3); param_names_.push_back(nm3);
	param_types_.push_back(tp4); param_names_.push_back(nm4);
	param_types_.push_back(tp5); param_names_.push_back(nm5);
}

void native_rule_entry::register_in_context(jam_context *ctx)
{
	bool is_user=module_!=JAM_ROOT_MODULE_NAME;
	jam_module_ptr module=ctx->bind_module(module_,is_user);
	jam_rule_ptr rule(new native_rule(*this,ctx,module.get()));
	module->register_rule(rule,true);
}

///////////////////////////////////////////////////////////////////////////////////////
////// Create and register native rules in the given context
///////////////////////////////////////////////////////////////////////////////////////
void register_root_module(jam_context *ctx);

void create_natives_for_context(jam_context *ctx)
{
	register_root_module(ctx);
}
